import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mziot/app/data/device_list_entity.dart';
import 'package:mziot/app/modules/devices/device_provider.dart';
import 'package:mziot/app/tools/global_const.dart';
import 'package:mziot/app/tools/tools.dart';

//UP,NODE_ID,GWID,PROD_ID,F_VERSION,ACCID,MESHED,PROVISONED,RSSID,RPASS,
//WIFICHANNEL,LIGHT_MODE,ONOFF,BRIGHT,LAST_ADC_BRIGHT,WIFICONNECTED,NOW,MEM
// 0|58BF2517033C|58BF2517033C|0|0|HOME_MESH|Tianshivsm1|cmd|0|100|58|1609859446|56648
// 命令ID，节点ID，网关节点ID，产品ID，固件版本，绑定账号，是否本地配网，是否路由器配网，路由器SSID，
// 路由器密码，路由器频段，设备控制状态，开关状态，亮度，ADC控制亮度，wifi是否链接成功，设备现在时间，设备内存
class BlueDeviceInfo {
  //命令ID
  String? cmdId;

  //节点ID
  String? nodeId;

  //网关节点ID
  String? netId;

  //产品ID
  String? productId;

  //固件版本
  String? hardVersion;

  //绑定账号
  String? accountId;

  //是否本地配网
  int? local;

  //是否路由器配网
  int? network;

  //路由器SSID
  String? ssid;

  //路由器密码
  String? password;

  //路由器频段
  String? netRange;

  //设备控制状态
  String? cmdType;

  //开关状态
  int? turnState;

  //亮度
  int? lighting;

  //ADC控制亮度
  int? adcLighting;

  //wifi是否链接成功
  int? isWifi;

  //设备现在时间
  String? time;

  //设备内存
  String? memory;

  //时间戳
  int? timestamp;

  //蓝牙
  bool? isBluetooth;
}

class BlueService {
  static BlueService share = BlueService();
  final serId = '83677baa-3eb8-4866-b6b6-96e5ed5cc48d';
  final readId = '6f588463-f8f1-44f8-bdae-a1272a1b0f6e';
  final writeId = 'f5d2b3fe-e6b5-49b5-aa5f-a00bb4156d1d';
  List<DeviceListList> deviceList = [];
  List<BlueDeviceInfo> localDevices = [];
  final flutterBlue = FlutterReactiveBle();
  QualifiedCharacteristic? readCharacteristic;
  QualifiedCharacteristic? writeCharacteristic;
  DeviceConnectionState deviceState = DeviceConnectionState.disconnected;

  StreamSubscription? readListen;
  StreamSubscription? scanListen;
  StreamSubscription? connectListen;
  DiscoveredDevice? currentDevice;
  var isAll = false;
  final isScaning = false.obs;
  var blueIsOpen = false;
  var isAdd = false;
  var isAsync = false;
  List<String> deleteIds = [];

  BlueService() {
    flutterBlue.statusStream.listen((event) {
      debugPrint('blue switch state $event');
      if (event == BleStatus.ready) {
        blueIsOpen = true;
        scanDevices();
      } else {
        final isOpen = Get.isDialogOpen ?? false;
        if (event != BleStatus.unknown && !isOpen) {
          MPermission.instance.bluetooth();
        }
        blueIsOpen = false;
        localDevices.forEach((element) {
          element.isBluetooth = false;
        });
        deviceList.forEach((element) {
          element.isBluetooth.value = false;
        });
        deviceState = DeviceConnectionState.disconnected;
        disConnectDevice();
      }
    });

    flutterBlue.connectedDeviceStream.listen((event) {
      if (deviceState != event.connectionState) {
        deviceState = event.connectionState;
      }
    });
  }

  BlueDeviceInfo? deviceInfo(String? deviceId) {
    final did = deviceId?.replaceAll(':', '');

    BlueDeviceInfo? info;
    localDevices.forEach((element) {
      if (element.nodeId == did) {
        info = element;
        return;
      }
    });

    return info;
  }

  Future<dynamic> stopScan() async {
    await scanListen?.cancel();
    scanListen = null;
    isScaning.value = false;
    return Future.value();
  }

  ///扫描设备
  Future<dynamic> scanDevices() async {
    if (!blueIsOpen) {
      return;
    }
    await stopScan();
    await disConnectDevice();

    isScaning.value = true;
    int scanCount = 0;
    final stream = flutterBlue
        .scanForDevices(withServices: [], scanMode: ScanMode.lowLatency);
    if (isAll) {
      return Future.value(stream);
    } else {
      bool isScan = false;
      scanListen = stream.listen((event) async {
        final device = filterDevice(event);
        if (scanCount == 1000) {
          scanCount = 0;
          debugPrint('is scanning ...');
        }
        scanCount++;
        if (!isScan && device != null) {
          await stopScan();
          isScan = true;
          connectDevice(device);
        }
      }, onError: (e) async {
        debugPrint('scanListen error ${e.toString()}');
        await stopScan();
      });
    }

    return Future.value();
  }

  ///筛选设备
  List<DiscoveredDevice> filterDevices(
      DiscoveredDevice device, List<DiscoveredDevice> devices) {
    List<DiscoveredDevice> copyDevices = List.from(devices);
    final names = device.name.split('_');
    var isContains = device.name.contains('MZ_MZ');
    if (names.length >= 3) {
      if (names[2] != '0') {
        isContains = false;
      } else if (isContains) {
        deleteIds.remove(names.last);
        final index =
            localDevices.indexWhere((element) => element.nodeId == names.last);
        if (index >= 0) {
          isContains = false;
          localDevices.removeWhere((element) => element.nodeId == names.last);
        }
      }
    }

    final index =
        copyDevices.indexWhere((element) => element.name == device.name);
    if (isContains && index == -1) {
      copyDevices.add(device);
    }
    if (devices.isNotEmpty) {
      final names = devices.map((e) => e.name);
      debugPrint('scan all filter devices $names');
    }
    return copyDevices;
  }

  DiscoveredDevice? filterDevice(DiscoveredDevice device) {
    if (isAll) {
      return null;
    }

    final name = 'MZ_MZ';
    final isContain = device.name.contains(name);
    if (isContain) {
      final names = device.name.split('_');
      final uid = GlobalConst.userModel?.userId ?? -1;
      final isDelete = deleteIds.indexWhere((element) => element == names.last);
      if (names[2] == uid.toString() && isDelete == -1) {
        debugPrint('scan filter device ${device.name}');
        return device;
      }
    }

    return null;
  }

  Future<void> connectDevice(DiscoveredDevice? device) async {
    if (deviceState != DeviceConnectionState.disconnected) {
      await disConnectDevice();
    }
    if (scanListen != null) {
      await scanListen?.cancel();
      scanListen = null;
    }
    if (connectListen != null) {
      connectListen?.cancel();
      connectListen = null;
    }

    debugPrint('connectDevice: ${device?.name}');
    connectListen = flutterBlue
        .connectToDevice(
      id: device!.id,
      connectionTimeout: Duration(seconds: 5),
    )
        // .connectToAdvertisingDevice(
        //     id: device!.id,
        //     withServices: [],
        //     prescanDuration: Duration(seconds: 3),
        //     connectionTimeout: Duration(seconds: 5))
        .listen((event) async {
      debugPrint('eventxxx: $event');
      if (deviceState != event.connectionState) {
        deviceState = event.connectionState;
        if (deviceState == DeviceConnectionState.disconnected) {
          localDevices.forEach((element) {
            element.isBluetooth = false;
          });
          deviceList.forEach((element) {
            element.isBluetooth.value = false;
          });
          disConnectDevice();
        } else if (deviceState == DeviceConnectionState.connected) {
          currentDevice = device;
          if (!isAdd && !isAsync) {
            DeviceProvider.execCmd().then((value) {
              BlueService.share.execCmds(value.data);
              isAsync = true;
            });
          }
          flutterBlue.requestMtu(deviceId: device.id, mtu: 512);
          sleep(Duration(seconds: 2));
          List<DiscoveredService> servers =
              await flutterBlue.discoverServices(device.id);
          DiscoveredService service = servers
              .firstWhere((element) => element.serviceId.toString() == serId);
          Uuid readCharId = service.characteristics
              .firstWhere(
                  (element) => element.characteristicId.toString() == readId)
              .characteristicId;
          readCharacteristic = QualifiedCharacteristic(
              characteristicId: readCharId,
              serviceId: service.serviceId,
              deviceId: device.id);
          Uuid writeCharid = service.characteristics
              .firstWhere(
                  (element) => element.characteristicId.toString() == writeId)
              .characteristicId;
          writeCharacteristic = QualifiedCharacteristic(
              characteristicId: writeCharid,
              serviceId: service.serviceId,
              deviceId: device.id);
          readListen = flutterBlue
              .subscribeToCharacteristic(readCharacteristic!)
              .listen((event) async {
            final info = await getInfo(event);
            if (info != null) {
              final index = localDevices
                  .indexWhere((element) => element.nodeId == info.nodeId);
              final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
              info.timestamp = now.toInt();

              if (deleteIds.contains(info.nodeId)) {
                localDevices
                    .removeWhere((element) => element.nodeId == info.nodeId);
                return;
              }
              if (index == -1) {
                localDevices.add(info);
              } else {
                localDevices[index] = info;
              }
              localDevices.forEach((element) {
                var diff = 0;
                if (element.timestamp != null) {
                  diff = now.toInt() - element.timestamp!;
                }
                if (diff >= 35) {
                  element.isBluetooth = false;
                } else {
                  element.isBluetooth = true;
                }
              });

              final sindex = deviceList.indexWhere(
                  (element) => element.deviceSerialnum == info.nodeId);
              if (sindex == -1) {
                return;
              }

              deviceList[sindex].isBluetooth.value = info.isBluetooth ?? false;
              deviceList[sindex].closeState.value =
                  info.turnState == 1 ? false : true;
              deviceList[sindex].lightRate.value = info.lighting ?? 0;
              deviceList[sindex].isWifi.value = info.isWifi == 1 ? true : false;
            }
          }, onError: (e) async {
            debugPrint('connect error ${e.toString()}');
            // await disConnectDevice();
          });
        }
        if (deviceState == DeviceConnectionState.connected ||
            deviceState == DeviceConnectionState.disconnected) {
          debugPrint('device state: $event');
          // showToast('蓝牙连接状态 $deviceState');
        }
      }
    });

    return Future.value();
  }

  Future<bool> disConnectDevice() async {
    debugPrint('disConnectDevice....');
    deviceState = DeviceConnectionState.disconnected;
    if (scanListen != null) {
      try {
        await scanListen?.cancel();
      } catch (_) {}
      scanListen = null;
    }
    if (readListen != null) {
      try {
        await readListen?.cancel();
      } catch (_) {}
      readListen = null;
    }
    if (connectListen != null) {
      try {
        sleep(Duration(milliseconds: 500));
        await connectListen?.cancel();
      } catch (_) {}
      connectListen = null;
    }
    if (currentDevice?.id != null) {
      try {
        await flutterBlue.clearGattCache(currentDevice!.id);
      } catch (_) {}
    }
    currentDevice = null;
    readCharacteristic = null;
    writeCharacteristic = null;
    return Future.value(true);
  }

  Future<bool> checkStatus() async {
    final isOpen = flutterBlue.status == BleStatus.ready;
    if (!isOpen) {
      // showToast('Bluetooth functionality is turned off');
      return Future.value(false);
    }

    if (deviceState != DeviceConnectionState.connected) {
      // showToast('Bluetooth disconnected');
      return Future.value(false);
    }

    return Future.value(true);
  }

  //本地组网
  Future<void> localCmd(String deviceId, String? meshKey) async {
    if (meshKey == null) {
      return Future.value();
    }
    final check = await checkStatus();
    if (!check) {
      return Future.value();
    }
    if (deviceState == DeviceConnectionState.disconnected) {
      return Future.value();
    }

    final uid = GlobalConst.userModel?.userId.toString() ?? 'actid';
    final cmd = '3|0|$uid|$deviceId|$uid|$meshKey';
    debugPrint('cmd: $cmd');
    await flutterBlue.writeCharacteristicWithResponse(writeCharacteristic!,
        value: utf8.encode(cmd));
  }

  //开关控制
  void turnCmd(List<String> deviceIds, bool open) async {
    final check = await checkStatus();
    if (!check) {
      return;
    }
    final uid = GlobalConst.userModel?.userId.toString() ?? 'actid';
    final ids = deviceIds.join(',');
    final cmd = '1|0|$uid|$ids|${open ? 1 : 0}';
    debugPrint('cmd: $cmd');
    await flutterBlue.writeCharacteristicWithResponse(writeCharacteristic!,
        value: utf8.encode(cmd));
  }

  //亮度控制
  void lightCmd(List<String> deviceIds, int light) async {
    final check = await checkStatus();
    if (!check) {
      return;
    }
    final uid = GlobalConst.userModel?.userId.toString() ?? 'actid';

    final ids = deviceIds.join(',');
    final cmd = '2|0|$uid|$ids|$light';
    debugPrint('cmd: $cmd');
    await flutterBlue.writeCharacteristicWithResponse(writeCharacteristic!,
        value: utf8.encode(cmd));
  }

  //设置Wi-Fi
  void wifiCmd(String? deviceId, String ssid, String password) async {
    final check = await checkStatus();
    if (!check) {
      return;
    }
    final uid = GlobalConst.userModel?.userId.toString() ?? 'actid';
    deviceId = deviceId ?? '';
    final cmd = '4|0|$uid|$deviceId|$ssid|$password';
    debugPrint('cmd: $cmd');
    return flutterBlue.writeCharacteristicWithResponse(writeCharacteristic!,
        value: utf8.encode(cmd));
  }

  //执行cmd命令
  Future<bool> execCmd(String cmd) async {
    final check = await checkStatus();
    if (!check || writeCharacteristic == null) {
      return Future.value(false);
    }
    debugPrint('cmd: $cmd');
    await flutterBlue.writeCharacteristicWithResponse(writeCharacteristic!,
        value: utf8.encode(cmd));
    return Future.value(true);
  }

  Future<BlueDeviceInfo?> getInfo(List<int> data) async {
    var info = BlueDeviceInfo();
    final dataText = utf8.decode(data);
    final params = dataText.split('|');

    if (params.length < 18) {
      return null;
    }
    DeviceProvider.updateDevices(dataText);
    debugPrint('report text: $dataText');

    info.cmdId = params[0];
    info.nodeId = params[1];
    info.netId = params[2];
    info.productId = params[3];
    info.hardVersion = params[4];
    info.accountId = params[5];
    info.local = int.parse(params[6]);
    info.network = int.parse(params[7]);
    info.ssid = params[8];
    info.password = params[9];
    info.netRange = params[10];
    info.cmdType = params[11];
    info.turnState = int.parse(params[12]);
    info.lighting = int.parse(params[13]);
    info.adcLighting = int.parse(params[14]);
    info.isWifi = int.parse(params[15]);
    info.time = params[16];
    info.memory = params[17];

    return info;
  }

  //执行命令
  Future<bool> execCmds(dynamic value) async {
    if (value is! Map<String, dynamic>) {
      return Future.value(false);
    }
    final check = await checkStatus();
    if (!check) {
      return Future.value(false);
    }
    final commandMap = value['commandMap'];
    if (commandMap is Map<String, dynamic>) {
      for (int i = 0; i < commandMap.length; i++) {
        final commands = commandMap['$i'] as List<dynamic>;
        for (int j = 0; j < commands.length; j++) {
          if (commands[j] is String) {
            await BlueService.share.execCmd(commands[j]);
          }
        }
      }
    }
    return Future.value(true);
  }
// 命令ID，节点ID，网关节点ID，产品ID，固件版本，绑定账号，是否本地配网，是否路由器配网，路由器SSID，
// 路由器密码，路由器频段，设备控制状态，开关状态，亮度，ADC控制亮度，wifi是否链接成功，设备现在时间，设备内存
}
